package com.libleveldb.implementation.mock

import com.libleveldb.Iterator
import com.libleveldb.exception.LevelDBClosedException
import com.libleveldb.exception.LevelDBIteratorNotValidException
import com.libleveldb.util.Bytes
import java.util.*

open class MockIterator(map: SortedMap<ByteArray, ByteArray>) : Iterator() {
    override var isClosed = false
    protected val snapshot: SortedMap<ByteArray, ByteArray> =
        Collections.unmodifiableSortedMap(TreeMap(map))
    protected val keys: ArrayList<ByteArray> = ArrayList(map.keys)
    var position = 0

    @get:Throws(LevelDBClosedException::class)
    override val isValid: Boolean
        get() {
            checkIfClosed()
            return position > -1 && position < keys.size
        }

    @Throws(LevelDBClosedException::class)
    override fun seekToFirst() {
        checkIfClosed()
        position = 0
    }

    @Throws(LevelDBClosedException::class)
    override fun seekToLast() {
        checkIfClosed()
        position = keys.size - 1
    }

    @Throws(LevelDBClosedException::class)
    override fun seek(key: ByteArray?) {
        checkIfClosed()
        position = Collections.binarySearch(keys, key, Bytes.COMPARATOR)
        if (position < 0) {
            position = -position - 1
        }
    }

    @Throws(LevelDBClosedException::class)
    override fun next() {
        checkIfClosed()
        if (!isValid) {
            throw LevelDBIteratorNotValidException()
        }
        position++
    }

    @Throws(LevelDBClosedException::class)
    override fun previous() {
        checkIfClosed()
        if (!isValid) {
            throw LevelDBIteratorNotValidException()
        }
        position--
    }

    @Throws(LevelDBClosedException::class)
    override fun key(): ByteArray? {
        checkIfClosed()
        if (!isValid) {
            throw LevelDBIteratorNotValidException()
        }
        return keys[position]
    }

    @Throws(LevelDBClosedException::class)
    override fun value(): ByteArray? {
        checkIfClosed()
        if (!isValid) {
            throw LevelDBIteratorNotValidException()
        }
        return snapshot[keys[position]]
    }

    override fun close() {
        isClosed = true
    }

    @Throws(LevelDBClosedException::class)
    protected fun checkIfClosed() {
        if (isClosed) {
            throw LevelDBClosedException("Iterator has been closed.")
        }
    }

    init {
        Collections.sort(keys, Bytes.COMPARATOR)
    }
}